/* \file solomon2dat.cpp
 *
 * Legge un'istanza di VRPTW nel formato di Solomon e la converte in un .dat per AMPL.
 * Termina di leggere il file di input quando incontra una riga vuota (no spazi, no tabs...).
 *
 * Usage: ./solomon2dat <solomon_instance_file> [K]
 * Compile: g++ -o solomon2dat solomon2dat.cpp
 *
 * \author Gionata Massi <massi@diiga.univpm.it>
 * \date 2010-10-02
 */
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
#include <list>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <libgen.h>

using namespace std;

struct node {
	int no;
	int xcoord;
	int ycoord;
	int demand;
	int ready_time;
	int due_date;
	int service_time;
};

struct bigM {
	int i;
	int j;
	double M;

	bigM(int ii, int jj, double MM) : i(ii), j(jj), M(MM) {}
};

string colortable[] = {
	"firebrick", "darkblue", "darkcyan",
	"darkmagenta", "chocolate", "darkgreen",
	"red", "green", "blue",
	"fuchsia", "lime", "navy",
	"orange", "orchid", "pink",
	"purple", "maroon", "violet"
    	"yellow", "magenta", "cyan",
};

int
main(int argc, char *argv[]) {
	ifstream instanceFile(argv[1]);
	if (instanceFile.fail()) {
		cerr << "Errore!" << endl;
		return 1;
	}
	
	int K, C;
	string line;
	for (int i = 0; i < 5; i++)
		getline(instanceFile, line);

	istringstream linestream(line);
	linestream >> K >> C;

	for (int i = 0; i < 5; i++)
		getline(instanceFile, line);
	
	int no;
	//list <node *> nodes;
	vector <node *> nodes;
	linestream.clear();
	linestream.str(line);
	while (!line.empty()) {
		linestream >> no;
		node *currNode = new node();
		currNode->no = no;
		linestream >> currNode->xcoord;
		linestream >> currNode->ycoord;
		linestream >> currNode->demand;
		linestream >> currNode->ready_time;
		linestream >> currNode->due_date;
		linestream >> currNode->service_time;
		nodes.push_back(currNode);
		getline(instanceFile, line);
		linestream.clear();
		linestream.str(line);
	}
	
	instanceFile.close();
	double lb, ub;
	
	K = min((int) K, (int) nodes.size() - 1);
	if (argc > 2)
		K = atoi(argv[2]);
	if (argc > 3)
		ub = strtod(argv[3], NULL);
	else
		ub = 1E6;
	if (argc > 4)
		lb = strtod(argv[4], NULL);
	else
		lb = 0.0;
	  
	cout << "data;" << endl << endl;

	cout << "param K := " << K << ";" << endl;
	cout << "param C := " << C << ";" << endl;
	int N = nodes.size() - 1;
	cout << "param N := " << N << ";" << endl;
	cout << "param E := " << nodes.front()->ready_time << ";" << endl;
	cout << "param L := " << nodes.front()->due_date << ";" << endl;
	cout << "param xcoord :=" << endl;
	for (vector <node *>::const_iterator i = nodes.begin(); i != nodes.end(); i++)
		cout << "\t" << (*i)->no << "\t" << (*i)->xcoord << endl;
	cout << "\t" << N+1 << "\t" << nodes.front()->xcoord << ";" << endl;
	cout << "param ycoord :=" << endl;
	for (vector <node *>::const_iterator i = nodes.begin(); i != nodes.end(); i++)
		cout << "\t" << (*i)->no << "\t" << (*i)->ycoord << endl;
	cout << "\t" << N+1 << "\t" << nodes.front()->ycoord << ";" << endl;
	cout << "param d :=" << endl;
	for (vector <node *>::const_iterator i = nodes.begin(); i != nodes.end(); i++)
		cout << "\t" << (*i)->no << "\t" << (*i)->demand << endl;
	cout << "\t" << N+1 << "\t" << nodes.front()->demand << ";" << endl;
	cout << "param s :=" << endl;
	for (vector <node *>::const_iterator i = nodes.begin(); i != nodes.end(); i++)
		cout << "\t" << (*i)->no << "\t" << (*i)->service_time << endl;
	cout << "\t" << N+1 << "\t" << nodes.front()->service_time << ";" << endl;
	cout << "param a :=" << endl;
	for (vector <node *>::const_iterator i = nodes.begin(); i != nodes.end(); i++)
		cout << "\t" << (*i)->no << "\t" << (*i)->ready_time << endl;
	cout << "\t" << N+1 << "\t" << nodes.front()->ready_time << ";" << endl;
	cout << "param b :=" << endl;
	for (vector <node *>::const_iterator i = nodes.begin(); i != nodes.end(); i++)
		cout << "\t" << (*i)->no << "\t" << (*i)->due_date << endl;
	cout << "\t" << N+1 << "\t" << nodes.front()->due_date << ";" << endl;

	int size = (N) * (N+1) / 2;
	vector <double> distance(size);
	for (int ii = 0; ii < N + 1; ii++)
		for (int jj = ii + 1; jj < N+ 1; jj++) {
			int idx = jj*(jj-1)/2+ii;
			// cout << idx << "(" << ii << ", " << jj << ") [" << size << "]" << endl;
			distance[idx] = 
				sqrt((nodes[ii]->xcoord - nodes[jj]->xcoord)*(nodes[ii]->xcoord - nodes[jj]->xcoord) + (nodes[ii]->ycoord - nodes[jj]->ycoord)*(nodes[ii]->ycoord - nodes[jj]->ycoord));
		}
	list <bigM> Mij;
	cout << "set arcs :=" << endl;
	for (int node = 1; node < N + 1; node++) {
		cout << "\t0\t" << node << "\t# " << distance[node*(node-1)/2] << endl;
		Mij.push_back(bigM(0, node, max(0.0, nodes[0]->due_date+nodes[0]->service_time+distance[node*(node-1)/2]-nodes[node]->ready_time)));
	}
	cout << "\t0\t" << N + 1 << "\t# 0" << endl;
	Mij.push_back(bigM(0, N+1, max(0.0, (double)nodes[0]->due_date-nodes[0]->ready_time)));
	for (int v = 1; v < N + 1; v++)
		for (int w = 1; w < N + 1; w++) {
			if (v == w)
				continue;
			int idx = (v < w) ? w*(w-1)/2+v: v*(v-1)/2+w;
			if (nodes[v]->ready_time + nodes[v]->service_time + distance[idx] <= nodes[w]->due_date && nodes[v]->demand + nodes[w]->demand <= C) {
				cout << "\t" << v << "\t" << w << "\t# " << distance[idx] << endl;
				Mij.push_back(bigM(v, w, max(0.0, nodes[v]->due_date+nodes[v]->service_time+distance[idx] - nodes[w]->ready_time)));
			}
		}
	for (int node = 1; node < N + 1; node++) {
		cout << "\t" << node << "\t" << N+1 << "\t# " << distance[node*(node-1)/2] << endl;
		Mij.push_back(bigM(node, N+1, max(0.0, nodes[node]->due_date+nodes[node]->service_time+distance[node*(node-1)/2]-nodes[0]->ready_time)));
	}
	cout << "\t;" << endl;

	cout << "param M :=" << endl;
	for (list<bigM>::const_iterator i = Mij.begin(); i != Mij.end(); i++)
		cout << "\t" << i->i << "\t" << i->j << "\t" << i->M << endl;
	cout << "\t;" << endl;
	
	cout << "param graphFileName := \"" << basename(argv[1]) << ".dot\";" << endl; 

	cout << "param tripcolor :=" << endl;
	for (int color = 0; color < K; color++)
		cout << "\t" << color + 1 << " \"" << colortable[color] << "\"" << endl;
	cout << "\t;" << endl;

	cout << fixed;

	// ub *= 1.01;
	cout << "param aga_ub := " << setprecision (6) << ub << ";" << endl;
	
	cout << "param tsp_lb := " << setprecision (6) << lb << ";" << endl;
	
	cout << endl << "end;" << endl;

	//system("pause");

	return 0;
}
